/**
 * @author ashok
 * Chatter Notifier App. 
 *
 * Schedulable class responsible for sending notifictions for chatter Notifier. 
 *
 * Copyright:  Copyright 2010
 * 
 * This file is part of Chatter Notifier. 
 * 
 * Chatter Notifier is free software: you can redistribute it and/or modify
 * it under the terms of the New BSD license.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 */
global class ScheduledChatterNotification implements Schedulable{ 
    private static final String BIRTHDAY_NOTIFICATION = 'birthday';
    private static final String ANNIVERSARY_NOTIFICATION = 'anniversary';
    
    global void execute(SchedulableContext ctx) { 
        List<User> userList = [select id, CurrentStatus  from User];
        
        if(userList == null) { 
            return;
        }
        
        for(User user : userList) {
        	Chatter_Profile__c selectUserChatterProfile = null;
        	try {
            	 selectUserChatterProfile = [Select Id, Name, User__c, Birthday__c, Sex__c, Relationship_Status__c,
                                                 Anniversary__c, Birthday_display__c,  Birthday_Notification__c, Anniversary_Notification__c,
                                                 Event_Notification__c From Chatter_Profile__c where User__c = : user.Id]; 
        	} catch(QueryException e) {
				selectUserChatterProfile = null;
			}                                                 
            
            // If there is no chatter profile associated with selected user then continue to next user.
            if(selectUserChatterProfile == null) {
                continue;
            }                                    
            
            Map<String, EntitySubscription> followingMap = ChatterUtil.getFollowingUserList(user.Id);
            
            Set<String> followingIds = followingMap.keySet();
            
            List<Chatter_Profile__c> chatterProfiles = [Select Id, Name, User__c, Birthday__c, Sex__c, Relationship_Status__c,
                                                 Anniversary__c, Birthday_display__c,  Birthday_Notification__c, Anniversary_Notification__c,
                                                 Event_Notification__c From Chatter_Profile__c where User__c IN : followingIds and IsDeleted = false];
            
            // filter out all the chatterProfile whose birthday lies in current week
            List<Chatter_Profile__c> birthdayChatterProfiles = getCPForBirthdayInCurrentWeek(chatterProfiles);
            postScheduledNotification(user.Id, birthdayChatterProfiles, BIRTHDAY_NOTIFICATION, followingMap);
            
            // filter out all the chatterProfile whose birthday lies in current week
            List<Chatter_Profile__c> anniversaryChatterProfiles = getCPForAnniversaryInCurrentWeek(chatterProfiles);
            postScheduledNotification(user.Id, anniversaryChatterProfiles, ANNIVERSARY_NOTIFICATION, followingMap);
        }                                
    }
    
    private void postScheduledNotification(Id userId, List<Chatter_Profile__c> chatterProfiles, String notificationType, Map<String, EntitySubscription> followingMap) {
        if(chatterProfiles == null || chatterProfiles.isEmpty()) {
            return; 
        } 
        Integer esCount = chatterProfiles.size();
        String textMessage = 'You have '+ esCount +' friend with a '+ notificationType +' this week. Help him celebrate by posting'+
                             ' a message on his Wall or sending him a Gift.';
                             
        for(Chatter_Profile__c cp : chatterProfiles) {              
            EntitySubscription es = followingMap.get(cp.User__c); 
            textMessage += '\n';
            if(notificationType == BIRTHDAY_NOTIFICATION) {
                textMessage += '\n  ' + ChatterUtil.getFormatedBirthdayDate(cp.Birthday__c, cp.Birthday_display__c, ChatterUtil.DIPLAY_ON_FEED);
            } else if (notificationType == ANNIVERSARY_NOTIFICATION) {
                textMessage += '\n  ' + ChatterUtil.getFormatedBirthdayDate(cp.Anniversary__c, null, ChatterUtil.DIPLAY_ON_FEED);
            }
            textMessage += '\n  ' + es.parent.name;
            textMessage += '\n';                                
        }
        FeedPost feedPost = new FeedPost();
        feedPost.ParentId = userId;
        feedPost.Body = textMessage; 
        insert feedPost;
    }
    
    private List<Chatter_Profile__c> getCPForBirthdayInCurrentWeek(List<Chatter_Profile__c> chatterProfiles) {
        List<Chatter_Profile__c> filteredCPList = new List<Chatter_Profile__c>(); 
        
        Date weekStartDate = System.today();  // TODO need to confirm start date.
        Date weekEndDate = weekStartDate.toStartOfWeek().addDays(7);
        
        for(Chatter_Profile__c cp : chatterProfiles) {
            // If the user has disabled his birthday notification, his birthday will 
            // not be notified to his followers.
            if(cp.Birthday_Notification__c == false) {
                continue;
            }
            Date birthday = cp.Birthday__c;
            if(birthday.day() >= weekStartDate.day() && birthday.day() <= weekEndDate.day()
                && birthday.month() >= weekStartDate.month() && birthday.month() <= weekEndDate.month()) {
                filteredCPList.add(cp);
            }
        }       
        return filteredCPList; 
    }
    
    private List<Chatter_Profile__c> getCPForAnniversaryInCurrentWeek(List<Chatter_Profile__c> chatterProfiles) {
        List<Chatter_Profile__c> filteredCPList = new List<Chatter_Profile__c>(); 
        
        Date weekStartDate = System.today();  // TODO need to confirm start date.
        Date weekEndDate = weekStartDate.toStartOfWeek().addDays(7);
        
        for(Chatter_Profile__c cp : chatterProfiles) {
            // If the user has disabled his anniversary notification, his anniversary will 
            // not be notified to his followers.
            if(cp.Anniversary_Notification__c == false) {
                continue;
            }           
            Date anniversary = cp.Anniversary__c;
            if(anniversary.day() >= weekStartDate.day() && anniversary.day() <= weekEndDate.day()
                && anniversary.month() >= weekStartDate.month() && anniversary.month() <= weekEndDate.month()) {
                filteredCPList.add(cp);
            }
        }       
        return filteredCPList; 
    } 
}